'use strict';
const {
  Model,
  DataTypes,
  NOW,
  UUIDV4
} = require('sequelize');

/**
 * @title 擴展模型 調用init(attributes, options)
 * @param {*} sequelize 
 */
module.exports = (sequelize) => {
  /**
   * ❸ 实例: 添加自定義實例或類級別的方法
   */
  class Todo extends Model {
    /**
     * 定义关联的辅助方法。
     * 此方法不是Sequelize生命周期的一部分。[模型是ES6類。您可以非常輕鬆地添加自定義實例或類級別的方法。]
     * 模型/索引文件将自动调用此方法。
     */
    static associate(models) {
      // define association here
    }
    /**
     * 实例方法
     * @description 创建实例: `const jane = User.build({ name: "Jane" }); `
     * @description 创建实例: 不应new直接使用運算符來創建實例。相反，應使用build方法
     * @notice 保存实例: 实例无法与数据库通信(甚至不是异步); 调用其save才能真正保存在db `await jane.save();` -- 僅更新真正更改的字段(内部优化)
     * @notice 保存时部分更新: 仅: `jane.name = "Jane II"; jane.favoriteColor = "blue"; await jane.save({ fields: ['name'] }); `仅保存列名數組中存在的字段(部分更新)
     * @notice 创建&保存: create是將上面的build和save方法組合為一個方法的方法 - `const user = await User.create({ username: 'alice123', isAdmin: true}, { fields: ['username'] });`见"保存时部分更新"
     * @notice 实例序列化: 实例调用`.toJSON()`方法得到数据对象, 或者被`JSON.stringify(jane, null, 4)`正確編輯缩进格式
     * @notice 更新实例: `jane.name = "Ada"; await jane.save();`
     * @notice 删除实例: `await jane.destroy();`从库中删除
     * @notice 重新加載实例: `jane.name = "Ada"; await jane.reload();`被更改后可以复原
     * @notice 递增和递減整数值: increment和decrement實例方法 - 单个`const incrementResult = await jane.increment('age', { by: 2 })` 多个`await jane.increment({'age': 2,'cash': 100}` 数值相同`await jane.increment(['age', 'cash'], { by: 2 })`
     * @notice 提供 `get(this.getDataValue) - 仅改变实例记录,不会改变数据库的值` 和 set(this.setDataValue) 方法
     */
    getFullname() {
      console.log(this);
    }
  };
  /**
   * ❷ init参数
   * @param {Object} ❷.❶ field's options
   * @param {Object} ❷.❷ Other model options
   */
  Todo.init({
    id: {// 可省略(默认id为主键)
      type: DataTypes.INTEGER,
      primaryKey: true,// 主键
      autoIncrement: true,
    },
    name: {
      type: DataTypes.STRING,
      allowNull: false
    },
    todoId: {
      type: DataTypes.UUID,
      defaultValue: UUIDV4,
      field: 'todo_id',
    },
    deadline: {
      type: DataTypes.DATE,
      defaultValue: NOW
      // This way, the current date/time will be used to populate this column (at the moment of insertion)
    },
    content: DataTypes.STRING,
    status: {
      type: DataTypes.INTEGER,
      defaultValue: 1
    },
  }, {
    sequelize,
    modelName: 'Todo', // 模型名称
    // freezeTableName: true // 強製表名稱等於模型名稱,不复数化(可局部或全局定义) - 通过inflection库实现
    underscored: true,
    paranoid: true,
    timestamps: true,// 自動添加領域createdAt和updatedAt每一個模型
    // createdAt: false,// @type {Boolean|String}
    // updatedAt: 'updateTimestamp',// 重命名字段
    // deletedAt: 'destroyTime',

    // 软删除: 特殊列deletedAt的值將設置為該刪除請求的時間戳; 且需要時間戳才能起作用
    // `await post.destroy(); 软删除` restore恢复软删除 `await post.destroy({ force: true }); 硬删除`
    // paranoid: true,
    // 由Sequelize執行的每個查詢將自動忽略軟刪除的記錄（當然，原始查詢除外）; `paranoid: false`让Sequelize不忽略

    hooks: {
      // https://sequelize.org/master/manual/hooks.html
    },

    // 范围: https://sequelize.org/master/manual/scopes.html

    // 在上面的属性中使用`unique：true`与在模型的选项中创建索引完全相同:
    // indexes: [{ unique: true, fields: ['someUnique'] }]
  });
  /**约束与验证
   * type         {DataTypes} 类型定义
   * primaryKey   {Boolean} 是否为主键
   * allowNull    {Boolean} 是否允许为null
   * defaultValue {any} 默认值
   * unique       {Boolean|'compositeIndex'} 创建唯一约束,字段值不能重复
   * autoIncrement {Boolean} 创建自动递增整数列
   * field        {String} 重写列名称(驼峰换成_)
   * comment      {String} 注释只能添加到MySQL，MariaDB，PostgreSQL和MSSQL中的列
   * references: {
      model: Bar,// 外链模型
      key: 'id',// 列名
      deferrable: Deferrable.INITIALLY_IMMEDIATE // With PostgreSQL
    } 创建外键其他模型
   */
  return Todo;
};

/**
 * ❶ DataTypes
 文本
 * DataTypes.STRING             // VARCHAR(255)
 * DataTypes.STRING(1234)       // VARCHAR(1234)
 * DataTypes.STRING.BINARY      // VARCHAR BINARY
 * DataTypes.TEXT               // TEXT
 * DataTypes.TEXT('tiny')       // TINYTEXT
 * DataTypes.CITEXT             // CITEXT          PostgreSQL and SQLite only.
 布尔
 * DataTypes.BOOLEAN            // TINYINT(1)
 数字
 * DataTypes.INTEGER            // INTEGER
 * DataTypes.BIGINT             // BIGINT
 * DataTypes.BIGINT(11)         // BIGINT(11)

 * DataTypes.FLOAT              // FLOAT
 * DataTypes.FLOAT(11)          // FLOAT(11)
 * DataTypes.FLOAT(11, 10)      // FLOAT(11,10)

 * DataTypes.REAL               // REAL            PostgreSQL only.
 * DataTypes.REAL(11)           // REAL(11)        PostgreSQL only.
 * DataTypes.REAL(11, 12)       // REAL(11,12)     PostgreSQL only.

 * DataTypes.DOUBLE             // DOUBLE
 * DataTypes.DOUBLE(11)         // DOUBLE(11)
 * DataTypes.DOUBLE(11, 10)     // DOUBLE(11,10)

 * DataTypes.DECIMAL            // DECIMAL
 * DataTypes.DECIMAL(10, 2)     // DECIMAL(10,2)

 * DataTypes.INTEGER.UNSIGNED
 * DataTypes.INTEGER.ZEROFILL
 * DataTypes.INTEGER.UNSIGNED.ZEROFILL
 日期
 * DataTypes.DATE     // 2021-02-22 16:50:49
 * DataTypes.DATE(6)  // 2021-02-22 16:50:49.398000
 * DataTypes.DATEONLY // 2021-02-22
 UUID
 * DataTypes.UUID     // UUIDV4 或者 UUIDV1
 虛擬領域
 * DataTypes.VIRTUAL  // 該VIRTUAL字段不會導致表中的列存在,但实例中存在; 或者不建议的getterMethods 和 setterMethods实现虚拟列

 * DataTypes.BLOB    二进制
 * DataTypes.RANGE(DataTypes.DATE)   日期范围
      const range = [
        { value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
        { value: new Date(Date.UTC(2016, 1, 1)), inclusive: true },
      ];
      // '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]'
 * DataTypes.JSON   JSON格式
 * DataTypes.ENUM('foo', 'bar')  枚举
 * 
 */

/**
 * ❹ CRUD ❺
 * `const users = await User.findAll();`  ==  SELECT * FROM ...  #查询所有字段
 * `Model.findAll({ attributes: ['foo', 'bar'] });`  ==  SELECT foo, bar FROM ...
 * `Model.findAll({ attributes: ['foo', ['bar', 'baz'], 'qux'] });`  ==  SELECT foo, bar AS baz, qux FROM ...  #嵌套数组来重命名属性
 * 
 * `Model.findAll({ attributes: [ 'foo', [sequelize.fn('COUNT', sequelize.col('hats')), 'n_hats'], 'bar' ] });`  ==  SELECT foo, COUNT(hats) AS n_hats, bar FROM ...  #instance.n_hats(fn-聚合)
 * `const instance = Model.findAll({ attributes: [ 'foo', 'hats', [sequelize.fn('COUNT', sequelize.col('hats')), 'n_hats'], 'bar' ] });`  ==  SELECT id, foo, bar, baz, qux, hats, COUNT(hats) AS n_hats FROM ...  #instance.n_hats以及instance.hats(fn-聚合)
 * 
 * `Model.findAll({ attributes: { exclude: ['baz'] } });`  ==  SELECT id, foo, bar, qux FROM ...  #排除字段
 */





